from django.contrib.postgres.fields import ArrayField
from django.db import models, transaction
from django.core.validators import MinValueValidator, MaxValueValidator, RegexValidator
# Create your models here.


class CreditGlobalAction(models.Model):
    """全局信誉配置表"""
    STRATEGY_LEVELS = (
        (0, '安全用户访问控制'),
        (1, '低风险用户访问控制'),
        (2, '中风险用户访问控制'),
        (3, '高风险用户访问控制'),
    )
    CONFIG_TYPE = (
        (1, "基础配置"),
        (2, "高级配置")
    )
    TRIGGER_ACTION = (
        (1, "访问低敏感应用"),
        (2, "访问中敏感应用"),
        (3, "访问高敏感应用"),
        (4, "访问低敏感应用子模块"),
        (5, "访问中敏感应用子模块"),
        (6, "访问高敏感应用子模块")
    )
    CHOOSE_STATUS = (
        (0, "未勾选"),
        (1, "已勾选")
    )

    level = models.PositiveSmallIntegerField(                   # 危险等级
        default=1, choices=STRATEGY_LEVELS
    )
    sen_mark = models.IntegerField(default=0)     # 敏感应用配置选项
    config_type = models.IntegerField(default=1, choices=CONFIG_TYPE)     # 配置级别   基础配置  高级配置
    status = models.IntegerField(default=0, choices=CHOOSE_STATUS)     # 勾选情况
    enabled = models.BooleanField(default=False)     # 全局启用情况
    score_lower = models.IntegerField(null=True)    # 区间下限
    score_upper = models.IntegerField(null=True)    # 区间上限

    @classmethod
    def get_user_level(cls, score):
        level_map = {
            0: "安全用户", 1: "低风险用户", 2: "中风险用户", 3: "高风险用户"
        }
        level = cls.objects.filter(score_lower__lte=score, score_upper__gte=score).first()
        if level:
            return level_map[level.level]
        else:
            return "-"

    class Meta:
        db_table = '"ztp"."credit_global_action"'


class SafetyCreditEvaluation (models.Model):
    """全局信誉配置表"""
    MODULE_MAPPING = (
        (1, '身份认证'),
        (2, '设备登录'),
        (3, '安全基线'),
        (4, '终端威胁'),
        (5, '资源请求'),
    )

    module = models.IntegerField(                   # 1. 身份认证 2.设备登录 3.安全基线 4.终端威胁 5.资源请求
        default=1, choices=MODULE_MAPPING
    )
    weight = models.IntegerField(default=100)     # 权重
    unit = models.CharField(
        max_length=50)     # 策略指标单元
    uid = ArrayField(models.CharField(max_length=20), default=[""])      #
    score = models.IntegerField(default=3)     # 分数

    class Meta:
        db_table = '"ztp"."safety_credit_evaluation"'


class StrategyGlobalAction(models.Model):
    """全局威胁策略处置表"""
    STRATEGY_LEVELS = (
        (0, '其他'),
        (1, '低危'),
        (2, '中危'),
        (3, '高危'),
    )
    TRIGGER_ACTION = (
        (1, '提示用户自行处理'),
        (2, '强制下线'),
        (3, '冻结用户{action_period_global}小时'),
        (4, '禁用用户'),
    )
    CHOOSE_STATUS = (
        (0, "未勾选"),
        (1, "已勾选")
    )

    level = models.PositiveSmallIntegerField(                   # 策略危险等级
        default=1, choices=STRATEGY_LEVELS
    )
    action = models.IntegerField(default=0, choices=TRIGGER_ACTION)     # 执行动作
    status = models.IntegerField(default=0, choices=CHOOSE_STATUS)     # 勾选情况
    enabled = models.BooleanField(default=False)     # 启用情况
    action_period = models.IntegerField(default=60)  # 行为持续时间, 默认为 60 ,六十分钟. 单位m

    class Meta:
        db_table = '"ztp"."strategy_global_action"'

class Strategy(models.Model):
    """策略模型"""
    STRATEGY_LEVELS = (
        # (0, '其他'),
        (1, '低危'),
        (2, '中危'),
        (3, '高危'),
    )
    TRIGGER_ACTION = (
        (0, '无'),
        (1, '冻结用户'),
        (2, '封禁用户'),
        (3, '短信二次认证'),
        (4, '动态验证码二次认证'),
        (5, '图形验证码'),
        (6, '本次禁止登录'),
        (7, '提示用户'),
        (8, '生成并记录风险日志'),
        # (9, '禁止登录'),
    )
    STRATEGY_CHANNELS = (
        (0, '不区分渠道'),
        (1, 'Android'),
        (2, 'Windows'),
        (3, 'Web'),
        (4, 'Linux'),
    )

    name = models.CharField(max_length=64, default='')          # 策略名称
    description = models.TextField()                            # 策略描述
    level = models.PositiveSmallIntegerField(                   # 策略危险等级
        default=1, choices=STRATEGY_LEVELS
    )
    channel = models.PositiveSmallIntegerField(                 # 策略涉及渠道，表示适配，默认为0，不区分渠道
        default=0, choices=STRATEGY_CHANNELS)
    # channel_str = models.CharField(max_length=64, null=True)    # 策略渠道
    weight = models.PositiveIntegerField(default=1)             # 策略分值
    category = models.CharField(max_length=64)                  # 策略类型
    uid = models.CharField(max_length=20, unique=True)          # 策略唯一标识符
    enabled = models.BooleanField(default=True)                 # 是否启用
    priority = models.PositiveIntegerField(default=1)           # 优先级, 1 最优先
    trigger_times = models.IntegerField(default=3)              # 触发次数
    trigger_period = models.IntegerField(default=10)            # 触发周期时间, 默认为 10 ,十分钟. 单位m
    action = models.IntegerField(default=0, choices=TRIGGER_ACTION)
    action_times = models.IntegerField(default=3)               # 行为持续次数
    action_period = models.IntegerField(default=15)             # 行为持续时间, 默认为 15 ,十分钟. 单位m

    start_time = models.CharField(
        max_length=20,
        validators=[RegexValidator(r'^([01]?[0-9]|2[0-3]):[0-5][0-9]$', '时间格式错误')],
        blank=True,  # 允许字段为空
        null=True,  # 允许字段为NULL（仅当数据库支持时）
    )  # 异常时间登录，起始时间
    end_time = models.CharField(
        max_length=20,
        validators=[RegexValidator(r'^([01]?[0-9]|2[0-3]):[0-5][0-9]$', '时间格式错误')],
        blank=True,  # 允许字段为空
        null=True,  # 允许字段为NULL（仅当数据库支持时）
    )  # 异常时间登录，结束时间

    num_value = models.IntegerField(
        validators=[MinValueValidator(0), MaxValueValidator(100000000)],
        blank=True,  # 允许字段为空
        null=True,   # 允许字段为NULL（仅当数据库支持时）
        )  # 用于一些数值字段

    type_value = models.IntegerField(
        validators=[MinValueValidator(0), MaxValueValidator(10)],
        blank=True,  # 允许字段为空
        null=True,   # 允许字段为NULL（仅当数据库支持时）
        )  # 用于一些不固定类型,如可选框里面的时间单位，分钟，小时，天

    # ------------------------------------------------------------------------------------------
    # 用于演示的新增字段，
    virus_time = models.CharField(
        max_length=20,
        validators=[RegexValidator(r'^([01]?[0-9]|2[0-3]):[0-5][0-9]$', '时间格式错误')],
        blank=True,  # 允许字段为空
        null=True,  # 允许字段为NULL（仅当数据库支持时）
    )  # 定时查毒，加入正则化校验

    VIRUS_DAY = (
        (0, '周一'),
        (1, '周二'),
        (2, '周三'),
        (3, '周四'),
        (4, '周五'),
        (5, '周六'),
        (6, '周日'),
    )
    virus_week_day = models.IntegerField(default=1, choices=VIRUS_DAY,
                                         blank=True,  # 允许字段为空
                                         null=True,  # 允许字段为NULL（仅当数据库支持时）
                                         )  # 按周定时查毒周几
    virus_month_day = models.IntegerField(
        validators=[MinValueValidator(1), MaxValueValidator(31)],
        blank=True,  # 允许字段为空
        null=True,   # 允许字段为NULL（仅当数据库支持时）
        )  # 按月定时查毒日期

    PRO_RANGE = (
        (0, '关键目录'),
        (1, '全盘文件'),
    )
    file_protect = models.IntegerField(default=1, choices=PRO_RANGE,
                                       blank=True,  # 允许字段为空
                                       null=True,  # 允许字段为NULL（仅当数据库支持时）
                                       )  # 文件防护目录范围

    @transaction.atomic()
    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
        if not self._state.adding:
            StrategyApplyRecord.objects.create(strategy=self)
        super().save(force_insert, force_update, using, update_fields)


class StrategyApplyRecord(models.Model):
    """策略应用（下发）记录"""
    strategy = models.ForeignKey(                               # 外键关联策略id
        'Strategy',
        on_delete=models.CASCADE
    )
    apply_time = models.DateTimeField(auto_now_add=True)        # 应用时间


class LoginLocation(models.Model):
    """用户登录地点记录"""
    username = models.CharField(max_length=100, unique=True)    # 用户名
    last_location = models.CharField(max_length=50)             # 上次登陆地
    last_time = models.DateTimeField(auto_now=True)             # 上次登录时间
    weekly_location = models.CharField(                         # 最近一周登陆地
        max_length=50, null=True
    )
    weekly_expiration = models.DateTimeField()                  # 周更新时间
    monthly_location = models.CharField(                        # 最近一个月登陆地
        max_length=50, null=True
    )
    monthly_expiration = models.DateTimeField()                 # 月更新时间


class SensitiveWord(models.Model):
    """敏感词库"""
    word = models.CharField(max_length=256, unique=True)        # 敏感词内容
    in_mail = models.BooleanField(default=True)                 # 是否在邮件策略中启用
    in_download = models.BooleanField(default=True)             # 是否在下载策略中启用
    in_share = models.BooleanField(default=True)                # 是否在分享策略中启用


class SecretFile(models.Model):
    """密级文件"""
    SECRET_LEVELS = (
        (0, '非密'),
        (1, '一级'),
        (2, '二级'),
        (3, '三级'),
    )

    name = models.CharField(max_length=256, unique=True)        # 文件名称
    md5 = models.CharField(max_length=32, unique=True)          # MD5
    level = models.PositiveSmallIntegerField(                   # 文件密级
        choices=SECRET_LEVELS
    )
    create_time = models.DateTimeField(auto_now_add=True)       # 创建时间
